package snafu.implementation.agents;

import java.awt.Color;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.List;

import snafu.framework.actions.AbstractAction;
import snafu.framework.actions.AbstractReaction;
import snafu.framework.agents.AgentBrain;
import snafu.framework.agents.AgentState;
import snafu.framework.agents.AgentStateItself;
import snafu.framework.objects.WorldObject;
import snafu.framework.senses.SenseItself;
import snafu.framework.view.Access;
import snafu.framework.worlds.Position;
import snafu.framework.worlds.Tile;
import snafu.framework.worlds.WorldMap;
import snafu.implementation.actions.collect.CollectIntention;
import snafu.implementation.actions.collect.CollectIntentionItself;
import snafu.implementation.actions.turn.left.TurnLeftIntention;
import snafu.implementation.actions.turn.left.TurnLeftIntentionItself;
import snafu.implementation.actions.turn.right.TurnRightIntention;
import snafu.implementation.actions.turn.right.TurnRightIntentionItself;
import snafu.implementation.actions.walk.forward.WalkForwardIntention;
import snafu.implementation.actions.walk.forward.WalkForwardIntentionItself;
import snafu.implementation.objects.gold.Gold;
import snafu.implementation.objects.pit.Pit;
import snafu.implementation.senses.stimuli.light.LightStimulus;
import snafu.implementation.senses.stimuli.light.LightStimulusItself;
import snafu.implementation.senses.stimuli.pressure.PressureStimulus;
import snafu.implementation.senses.stimuli.smell.SmellStimulus;
import snafu.implementation.states.literals.color.ColorLiteralItself;
import snafu.implementation.states.literals.depth.DepthLiteralItself;
import snafu.implementation.states.literals.direction.DirectionLiteral;
import snafu.implementation.states.literals.direction.DirectionLiteralItself;
import snafu.implementation.states.literals.position.PositionLiteral;
import snafu.implementation.states.literals.shape.ShapeLiteralItself;

public class GoldSeekingHiker extends AgentBrain {

	private List<AbstractAction> savedActions = new ArrayList<AbstractAction>();
	
	@Override
	public AgentStateItself getInitialState() {
		// create shape
		int[] xPoints = new int[] {0, -43, 43};
		int[] yPoints = new int[] {-50, 25, 25};
		Polygon p = new Polygon(xPoints, yPoints, 3);
		Rectangle r = new Rectangle(-50, -50, 100, 30);
		Area shape = new Area(p);
		shape.subtract(new Area(r));
		
		// create initial state
		AgentStateItself state = new AgentStateItself();
		
		// literals
		state.setLiteral(new DirectionLiteralItself(0, Access.PUBLIC));
		state.setLiteral(new ColorLiteralItself(Color.RED, Access.PUBLIC));
		state.setLiteral(new DepthLiteralItself(10, Access.PUBLIC));
		state.setLiteral(new ShapeLiteralItself(shape, Access.PUBLIC));
		
		// intentions
		state.setIntention(new WalkForwardIntentionItself(Access.PRIVATE));
		state.setIntention(new CollectIntentionItself(Access.PRIVATE));
		state.setIntention(new TurnLeftIntentionItself(Access.PRIVATE));
		state.setIntention(new TurnRightIntentionItself(Access.PRIVATE));
		
		// senses
		state.addSense(new SenseItself(SmellStimulus.class, 40, 60));
		state.addSense(new SenseItself(LightStimulus.class, 30, 60));
		state.addSense(new SenseItself(PressureStimulus.class, 10, 50));
		
		// stimuli
		state.addStimulus(new LightStimulusItself(30, 60));

		return state;
	}
	
	@Override
	public AbstractAction act(WorldMap perception, AgentState state) {
		
		Position position = state.getLiteral(PositionLiteral.class);
		Integer direction = state.getLiteral(DirectionLiteral.class, 0);
		
		// check if we already had a plan
		if (savedActions.size() > 0) {
			AbstractAction action = savedActions.remove(0);
			// if the action is still applicable return it, else plan new
			if (action.isApplicable(perception)) {
				return action;
			}
		}
	
		CollectIntention collect = state.getIntention(CollectIntention.class);
		
		// check if we're on gold
		WorldObject gold = perception.getObject(position, Gold.class);
		if (collect != null && collect.isApplicable(perception, state, gold)) {
			return collect.createAction(gold);
		}
		
		// check if gold is in the neighborhood
		List<Position> goldInNeighborhood = new ArrayList<Position>();
		for (Tile neighbor : perception.getNeighborhood(position)) {
			gold = neighbor.getObject(Gold.class);
			if (gold != null) {
				goldInNeighborhood.add(neighbor.getPosition());
			}
		}
		
		// if there's gold in the hood, construct a plan to get there and return the first step
		if (goldInNeighborhood.size() > 0) {
			// TODO plan the next steps
		}

		// walk or turn randomly
		List<AbstractAction> possibleActions = new ArrayList<AbstractAction>();
		WalkForwardIntention walk = state.getIntention(WalkForwardIntention.class);
		if (walk != null && walk.isApplicable(perception, state)) {
			Tile front = perception.getFrontTile(position, direction);
			// avoid walking on pits
			if (front.getObject(Pit.class) == null) {
				possibleActions.add(walk.createAction());
				possibleActions.add(walk.createAction());
			}
		}
		
		TurnLeftIntention left = state.getIntention(TurnLeftIntention.class);
		if (left != null && left.isApplicable(perception, state)) {
			possibleActions.add(left.createAction());
		}
		
		TurnRightIntention right = state.getIntention(TurnRightIntention.class);
		if (right != null && right.isApplicable(perception, state)) {
			possibleActions.add(right.createAction());
		}
		
		
		// return an action randomly
		int index = (int) (Math.random() * possibleActions.size());
		return possibleActions.get(index);
		
	}

	@Override
	public AbstractReaction react(AbstractAction action) {
		return null;
	}
	
	@Override
	public String output() {
		return "GoldSeekingHiker";
	}
}
